Amazon Athena Partition Projectionを用いたHiveパーティションのパーティションプルーニングの自動化
Hiveパーティション(カラム名ありパーティション)は、データレイクで一般的なファイルレイアウトです。本日は、year
、month
、day
のパーティションキーのテーブルに対してPartition Projectionを用いたHiveパーティションのパーティションプルーニングを通して、Hiveパーティションのレイアウト、複数カラム、digits指定について解説します。
今回は、Partition Projectionの応用編になりますので、Partition Projectionに基本については、以下のブログをご覧ください。
Hiveパーティション(カラム名ありパーティション)とは
データファイルを日付などのキー情報に基づきフォルダ毎に分割することをパーティションと言います。そのフォルダ名にキーと値の情報を指定する方式をHiveパーティション(カラム名ありパーティション)と言います。
Hiveパーティションは、MSCK REPIR TABLE
を実行するだけでパーティションを自動的に認識できるので、新規でデータレイクを作成する際に採用されることがよくあります。
year
、month
、day
のHiveパーティション構成
フォルダは、year
、month
、day
の順に階層的に格納されています。例えば、2014年1月1日のデータは、year=2014/month=01/day=01
の下にデータファイルが格納されます。
order_hp └── year=2014 └── month=01 ├── day=01 │ └── 20200707_121540_061186_2027485_0003_part_00.parquet ├── day=02 │ └── 20200707_121540_061186_2027485_0001_part_00.parquet ├── day=03 │ └── 20200707_121540_061186_2027485_0003_part_00.parquet ├── day=04 │ ├── 20200707_121540_061186_2027485_0001_part_00.parquet │ └── 20200707_121540_061186_2027485_0003_part_00.parquet ├── day=05 │ └── 20200707_121540_061186_2027485_0003_part_00.parquet : : : ├── day=29 │ ├── 20200707_121540_061186_2027485_0001_part_00.parquet │ ├── 20200707_121540_061186_2027485_0002_part_00.parquet │ └── 20200707_121540_061186_2027485_0003_part_00.parquet └── day=31 └── 20200707_121540_061186_2027485_0003_part_00.parquet
Partition Projectionの設定
Hiveパーティションのレイアウト、複数カラム、digits指定について解説します。
Hiveパーティションのレイアウトの指定
パーティションのパスは、year=2014/month=01/day=01
のようになるため、TBLPROPERTIESのstorage.location.template
はyear=${year}/month=${month}/day=${day}
のようにカラム名の「値」の箇所はプレースホルダに置き換えます。
よって、storage.location.template
は以下のように指定します。
'storage.location.template'='s3://<bucket_name>/order_hp/year=${year}/month=${month}/day=${day}',
複数カラムの指定
year=2014/month=01/day=01
のように3つのカラムの値を自動的に生成するには、year
、month
、day
のそれぞれのデータ範囲(range)やデータ型(type)、増分(interval)を指定します。
-- year 'projection.day.interval'='1', 'projection.day.range'='1,31', 'projection.day.type'='integer', -- month 'projection.month.interval'='1', 'projection.month.range'='1,12', 'projection.month.type'='integer', -- day 'projection.year.interval'='1', 'projection.year.range'='2014,2015', 'projection.year.type'='integer',
digits
の指定
例えば、day
のデータ型にinteger
を指定すると、1, 2, 3, 4, … 31
と連続しますが、フォルダに指定した実際の値は、01, 02, 03, 04, … 31
であるため、誤ったパーティションを設定し、データを参照できません。
そのため、数値の前に「0埋め」する指定するprojection.day.digits
に桁数を指定します。day
の場合は、01
〜31
の範囲なので、2
を指定します。
-- year 'projection.day.digits'='2', 'projection.day.interval'='1', 'projection.day.range'='1,31', 'projection.day.type'='integer', -- month 'projection.month.digits'='2', 'projection.month.interval'='1', 'projection.month.range'='1,12', 'projection.month.type'='integer', -- day 'projection.year.digits'='4', 'projection.year.interval'='1', 'projection.year.range'='2014,2015', 'projection.year.type'='integer',
全体のDDL
上記の全てを反映したDDLは、以下のとおりです。
CREATE EXTERNAL TABLE `order_hp`( `row_id` bigint, `order_id` varchar(32), `ship_date` varchar(10), `ship_mode` varchar(64), `customer_id` varchar(64), `customer_name` varchar(64), `segment` varchar(64), `country` varchar(16), `city` varchar(16), `state` varchar(16), `region` varchar(16), `product_id` varchar(255), `category` varchar(16), `sub_category` varchar(32), `product_name` varchar(255), `sales` double, `quantity` bigint, `discount` double, `profit` double) PARTITIONED BY ( `year` int, `month` int, `day` int) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 's3://<bucket_name>/order_hp' TBLPROPERTIES ( 'has_encrypted_data'='false', 'projection.enabled'='true', 'projection.day.digits'='2', 'projection.day.interval'='1', 'projection.day.range'='1,31', 'projection.day.type'='integer', 'projection.month.digits'='2', 'projection.month.interval'='1', 'projection.month.range'='1,12', 'projection.month.type'='integer', 'projection.year.digits'='4', 'projection.year.interval'='1', 'projection.year.range'='2014,2017', 'projection.year.type'='integer', 'storage.location.template'='s3://<bucket_name>/order_hp/year=${year}/month=${month}/day=${day}', 'transient_lastDdlTime'='1595867108')
別解:enumの利用
今回はキーが連続する数値でしたが、enum(列挙型)に値を列挙することも可能です。以下の例では、あえてenum(列挙型)を用いると以下のように定義出来ます。enumの実際のユースケースとしては、都道府県のように連続していない値、かつ列挙可能なカーディナリティが低いカラムに適しています。
CREATE EXTERNAL TABLE `order_hp_2`( `row_id` bigint, `order_id` varchar(32), `ship_date` varchar(10), `ship_mode` varchar(64), `customer_id` varchar(64), `customer_name` varchar(64), `segment` varchar(64), `country` varchar(16), `city` varchar(16), `state` varchar(16), `region` varchar(16), `product_id` varchar(255), `category` varchar(16), `sub_category` varchar(32), `product_name` varchar(255), `sales` double, `quantity` bigint, `discount` double, `profit` double) PARTITIONED BY ( `year` int, `month` int, `day` int) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat' LOCATION 's3://<bucket_name>/order_hp' TBLPROPERTIES ( 'has_encrypted_data'='false', 'projection.enabled'='true', 'projection.year.type' = 'enum', 'projection.year.values' = '2014,2016,2017', 'projection.month.type' = 'enum', 'projection.month.values' = '01,02,03,04,05,06,07,08,09,10,11,12', 'projection.day.type' = 'enum', 'projection.day.values' = '01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31', 'storage.location.template'='s3://<bucket_name>/order_hp/year=${year}/month=${month}/day=${day}', 'transient_lastDdlTime'='1595867108')
最後
これまで新規でデータレイクを作成するとき、ファイルレイアウトは、Hiveパーティション(カラム名ありパーティション)に指定するように勧めてきた手前、Amazon Athena のPartition Projectionが利用できることを確認しました。ついでにenumの例も紹介しましたが、本来enumは数値のように連続していない値かつ列挙可能なカーディナリティが低いカラムに用いてください。